﻿#ifndef XVARIANT_HPP
#define XVARIANT_HPP

#include <lpb_reflect/library/xtypelist.hpp>
#include <lpb_reflect/library/xvaluelist.hpp>
#include <iostream>
#include <variant>
#include <string>
#include <type_traits>
#include <memory>
#include "xvariant_tool.hpp"

//=====================================
//利用std::variant实现,需C++17支持
//=====================================

namespace NS_variant
{
	template<typename Tlist>
	struct __variant;

	template<typename ... types>
	struct __variant<TL::typelsit<types...>>;

	template <typename... types>
	struct __variant<TL::typelsit<types...>>
	{	
		using xvariant = std::variant<std::monostate, types...>;
		using TList = TL::typelsit<std::monostate, types...>;

		__variant() {
			m_data = std::monostate();
		}

		template<typename T>
		__variant(T t) {
			m_data = t;
		}

		template<typename T>
		__variant& operator=(T&& _Obj) {
			m_data = _Obj;
			return *this;
		}

		template<typename T,typename =
			std::enable_if_t<std::is_fundamental_v<T> || (std::is_class_v<T> && std::is_default_constructible_v<T>)>
		>
		operator T(){
			if (!isValid<T>()) {
				return T{};
			}
			return get<T>();
		}

		template <typename T>
		constexpr bool isValid()
		{  
            using seqs = NS_variant::TL_getConvertSeq_T<TList,TList,T>;
            return isContainer<seqs>::isContainerImpl(m_data.index());
		}

		//整数序列至少有一个
		template<typename T,typename TList>
		struct xget;

		template <typename T, unsigned int N, unsigned... seqs>
		struct xget<T, VL::valuelist<unsigned int, N, seqs...>>
		{
			static T xgetImpl(const xvariant &v)
			{
				if (std::get_if<N>(&v) != nullptr)
				{
					return (T)(std::get<N>(v));
				}
				else
				{
					return  xget<T, VL::valuelist<unsigned int, seqs...>>::xgetImpl(v);
				}
			}
		};

		template <typename T, unsigned int N>
		struct xget<T, VL::valuelist<unsigned int, N>>
		{
			static decltype(auto) xgetImpl(const xvariant &v)
			{
				return (T)(std::get<N>(v));
			}
		};

		template <typename T>
		decltype(auto) get()
		{
            using seqs = NS_variant::TL_getConvertSeq_T<TList,TList,T>;
			return xget<T,seqs>::xgetImpl(m_data);
		}

		//**************************************************
		//整数序列至少有一个
		template<typename T,typename TList>
		struct xget_pointer;

		template <typename T, unsigned int N, unsigned... seqs>
		struct xget_pointer<T, VL::valuelist<unsigned int, N, seqs...>>
		{
			static T* xgetImpl(xvariant *v)
			{
				if (std::get_if<N>(v) != nullptr)
				{
					return (T*)(std::get_if<N>(v));
				}
				else
				{
					return  xget_pointer<T, VL::valuelist<unsigned int, seqs...>>::xgetImpl(v);
				}
			}
		};

		template <typename T, unsigned int N>
		struct xget_pointer<T, VL::valuelist<unsigned int, N>>
		{
			static decltype(auto) xgetImpl(xvariant *v)
			{
				return (T*)(std::get_if<N>(v));
			}
		};

		template <typename T>
		decltype(auto) get_pointer()
		{
            using seqs = NS_variant::TL_getConvertSeq_T<TList,TList,T>;
			return xget_pointer<T,seqs>::xgetImpl(&m_data);
		}

		xvariant m_data;
	};
}

template<int index,int maxIndex,typename TList>
struct varaint_spreadImpl {
	using class_t = TL::TL_NthElement_t<TList, index>;
	using tmp_type1 = TL::TL_pushback_t<TList, std::shared_ptr<class_t>>;
	using tmp_type2 = TL::TL_pushback_t<tmp_type1, class_t*>;
	using tmp_type3 = TL::TL_pushback_t<tmp_type2, std::reference_wrapper<class_t>>;
	using result = typename varaint_spreadImpl<index + 1, maxIndex, tmp_type3>::result;
};

template<int maxIndex, typename TList>
struct varaint_spreadImpl<maxIndex, maxIndex, TList> {
	using class_t = TL::TL_NthElement_t<TList, maxIndex>;
	using tmp_type1 = TL::TL_pushback_t<TList, std::shared_ptr<class_t>>;
	using tmp_type2 = TL::TL_pushback_t<tmp_type1, class_t*>;
	using tmp_type3 = TL::TL_pushback_t<tmp_type2, std::reference_wrapper<class_t>>;
	using result = tmp_type3;
};

template<typename TList>
struct varaint_spread {
	using deduplicate_t = TL::TL_deduplicate_t<TList>;
	using result =typename varaint_spreadImpl<0, TL::TL_sizeof_v<deduplicate_t>- 1, deduplicate_t>::result;
};

template<typename ...Args>
struct myVariant_adapter {
	using myVariant = NS_variant::__variant<
				typename varaint_spread<
														TL::typelsit< int, unsigned int, short, unsigned short, char, float, double, std::string, Args...>
														>::result
				>;
};

#define XVARIANT_CLASSTYPE_REGISTR(...)		using myVariant =typename myVariant_adapter<__VA_ARGS__>::myVariant;
#endif